#include <unistd.h>
#include <assert.h>
#include "rw_lock.h"

inline int fetch_and_add(int *var, int value) {
	asm volatile(
		"lock; xaddl %%eax, %2"
		:"=a"(value) // output
		:"a" (value), "m" (*var) //input
		:"memory" );
	return value;
}

void rwlock_init(my_rwlock *plock) {
	assert(plock);
	plock->val = 0;
}


void rwlock_read(my_rwlock *plock) {
	assert(plock);
	__sync_synchronize();
//	if (__sync_val_add_and_fetch(&plock->val, 1) > 0)
	if (fetch_and_add(&plock->val, 1) >= 0)
		return;
	while (plock->val <= 0)
		sleep(0);
	
}

void rwlock_write(my_rwlock *plock) {
	assert(plock);
	while (__sync_val_compare_and_swap(&plock->val, 0, CAS_MIN) != 0)
		sleep(0);
}

void rwunlock_read(my_rwlock *plock) {
	assert(plock);
//	assert(__sync_val_add_and_fetch(&plock->val, -1) > 0);
	assert(fetch_and_add(&plock->val, -1) >= 0);
}

void rwunlock_write(my_rwlock *plock) {
	assert(plock);
//	assert(__sync_val_add_and_fetch(&plock->val, -CAS_MIN) < 0);
	assert(fetch_and_add(&plock->val, -CAS_MIN) < 0);
}
